﻿using OSGeo.OGR;
using OSGeo.OSR;
using RemoteSensingImageDirectServer.Models.Tile;
using RemoteSensingImageDirectServer.Untils.Pool;

namespace RemoteSensingImageDirectServer.Untils.ScopeSpace
{
    public class RasterEnvelope : Envelope
    {
        /// <summary>
        /// X方向的分辨率
        /// </summary>
        public double ResolutionX { get; set; }

        /// <summary>
        /// Y方向的分辨率
        /// </summary>
        public double ResolutionY { get; set; }


        public RasterEnvelope()
        {
        }

        /// <summary>
        /// 构造一个栅格数据的范围
        /// </summary>
        /// <param name="minX">左（最小X）</param>
        /// <param name="minY">下（最小Y）</param>
        /// <param name="maxX">右（最大X）</param>
        /// <param name="maxY">上（最大Y）</param>
        public RasterEnvelope(double minX, double minY, double maxX, double maxY)
        {
            MinX = minX;
            MinY = minY;
            MaxX = maxX;
            MaxY = maxY;
        }


        /// <summary>
        /// 构造一个栅格数据的范围
        /// </summary>
        /// <param name="minX">左（最小X）</param>
        /// <param name="minY">下（最小Y）</param>
        /// <param name="maxX">右（最大X）</param>
        /// <param name="maxY">上（最大Y）</param>
        /// <param name="resolutionX">width</param>
        /// <param name="resolutionY">height</param>
        public RasterEnvelope(double minX, double minY, double maxX, double maxY, double resolutionX, double resolutionY)
        {
            MinX = minX;
            MinY = minY;
            MaxX = maxX;
            MaxY = maxY;
            ResolutionX = resolutionX;
            ResolutionY = resolutionY;
        }

        /// <summary>
        /// 将范围转为字符
        /// </summary>
        /// <returns></returns>
        public override string ToString()
        {
            return string.Format("MinX:{0},MaxY:{1},MaxX:{2},MinY:{3},ResolutionX:{4},ResolutionY:{5}",
                                  MinX, MaxY, MaxX, MinY, ResolutionX, ResolutionY);
        }

        /// <summary>
        /// 将范围转为wkt
        /// </summary>
        /// <returns></returns>
        public string ToWkt()
        {
            var wkt = string.Format("POLYGON (({0} {1},{2} {3},{4} {5},{6} {7},{8} {9}))",
                                    this.MinX, this.MaxY,
                                    this.MaxX, this.MaxY,
                                    this.MaxX, this.MinY,
                                    this.MinX, this.MinY,
                                    this.MinX, this.MaxY);
            return wkt;
        }

        /// <summary>
        /// 根据瓦片范围及影像6参数，获取到瓦片范围相对于影像格网的绝对位置
        /// </summary>
        /// <param name="env">瓦片范围，需要包含四至范围</param>
        /// <returns>返回瓦片相对于影像格网的绝对位置TileRange</returns>
        public TileRange CalculateTileRange(RasterEnvelope env)
        {
            TileRange tileRange = new TileRange();

            //左上角的行列坐标---瓦片开始写入时的开始坐标(瓦片)
            double imageSize = this.ResolutionX * this.ResolutionY;//-像元大小
            //   (-像元大小 * (相对右边(左) - 瓦片左)/ (-像元大小) + 0.5

            tileRange.StartCol = (int)((this.ResolutionY * (env.MinX - this.MinX)) / imageSize + 0.5);
            tileRange.StartRow = (int)((this.ResolutionX * (env.MaxY - this.MaxY)) / imageSize + 0.5);

            //右下角的行列坐标----瓦片结束写入的结束坐标
            tileRange.EndCol = (int)((this.ResolutionY * (env.MaxX - this.MinX)) / imageSize + 0.5);
            tileRange.EndRow = (int)((this.ResolutionX * (env.MinY - this.MaxY)) / imageSize + 0.5);

            return tileRange;
        }

        /// <summary>
        /// 计算影像相交范围
        /// </summary>
        /// <param name="other">其他范围</param>
        /// <returns></returns>
        public RasterEnvelope Insersetect(Envelope other)
        {
            double MinX = Math.Max(this.MinX, other.MinX);
            double MinY = Math.Max(this.MinY, other.MinY);
            double MaxX = Math.Min(this.MaxX, other.MaxX);
            double MaxY = Math.Min(this.MaxY, other.MaxY);
            return new RasterEnvelope(MinX, MinY, MaxX, MaxY);
        }

        public RasterEnvelope Wgs84ToMercator()
        {
            var tile_wkt = string.Format("POLYGON (({0} {1},{2} {3},{4} {5},{6} {7},{8} {9}))",
                                     this.MinX, this.MaxY,
                                     this.MaxX, this.MaxY,
                                     this.MaxX, this.MinY,
                                     this.MinX, this.MinY,
                                     this.MinX, this.MaxY);

            var tile_geom = Ogr.CreateGeometryFromWkt(ref tile_wkt, OsrTransformPool.Instance().SRWGS84);
            tile_geom.SwapXY();
            tile_geom.TransformTo(OsrTransformPool.Instance().SRWebMercator);

            var pEnvelope = new RasterEnvelope();
            tile_geom.GetEnvelope(pEnvelope);

            double rowCount = (this.MinY - this.MaxY) / this.ResolutionY;
            double colCount = (this.MaxX - this.MinX) / this.ResolutionX;

            pEnvelope.ResolutionX = (pEnvelope.MaxX - pEnvelope.MinX) / colCount;
            pEnvelope.ResolutionY = (pEnvelope.MinY - pEnvelope.MaxY) / rowCount;

            tile_geom.Dispose();

            return pEnvelope;
        }

        public RasterEnvelope Wgs84ToOther(SpatialReference targetSpatial)
        {
            var tile_wkt = string.Format("POLYGON (({0} {1},{2} {3},{4} {5},{6} {7},{8} {9}))",
                                     this.MinX, this.MaxY,
                                     this.MaxX, this.MaxY,
                                     this.MaxX, this.MinY,
                                     this.MinX, this.MinY,
                                     this.MinX, this.MaxY);

            var tile_geom = Ogr.CreateGeometryFromWkt(ref tile_wkt, OsrTransformPool.Instance().SRWGS84);
            tile_geom.SwapXY();
            tile_geom.TransformTo(targetSpatial);

            var pEnvelope = new RasterEnvelope();
            tile_geom.GetEnvelope(pEnvelope);

            double rowCount = (this.MinY - this.MaxY) / this.ResolutionY;
            double colCount = (this.MaxX - this.MinX) / this.ResolutionX;

            pEnvelope.ResolutionX = (pEnvelope.MaxX - pEnvelope.MinX) / colCount;
            pEnvelope.ResolutionY = (pEnvelope.MinY - pEnvelope.MaxY) / rowCount;

            tile_geom.Dispose();

            return pEnvelope;
        }


        public RasterEnvelope MercatorToWgs84()
        {
            var tile_wkt = string.Format("POLYGON (({0} {1},{2} {3},{4} {5},{6} {7},{8} {9}))",
                                     this.MinX, this.MaxY,
                                     this.MaxX, this.MaxY,
                                     this.MaxX, this.MinY,
                                     this.MinX, this.MinY,
                                     this.MinX, this.MaxY);

            var tile_geom = Ogr.CreateGeometryFromWkt(ref tile_wkt, OsrTransformPool.Instance().SRWebMercator);
            tile_geom.TransformTo(OsrTransformPool.Instance().SRWGS84);
            tile_geom.SwapXY();

            var pEnvelope = new RasterEnvelope();
            tile_geom.GetEnvelope(pEnvelope);

            double rowCount = (this.MinY - this.MaxY) / this.ResolutionY;
            double colCount = (this.MaxX - this.MinX) / this.ResolutionX;

            pEnvelope.ResolutionX = (pEnvelope.MaxX - pEnvelope.MinX) / colCount;
            pEnvelope.ResolutionY = (pEnvelope.MinY - pEnvelope.MaxY) / rowCount;

            tile_geom.Dispose();

            return pEnvelope;
        }

    }
}
